#include "cpu.h"
#include "difftest.h"
#include "tracer/wave_tracer.h"
#include "device/device.h"

uint32_t total_cycles = 0;
static bool dump = false;
ITracer itracer;
void scan_all_wps();

bool is_device_addr(long long addr);
#ifdef __cplusplus
extern "C" {
#endif
    static uint64_t intr_pc;
    static bool submit_flag = false;
    void raise_hard_intr()
    {
        Log("raise_hard_intr");
        top->ex_intr = 0;
        difftest_raise_intr_ref(7|(1ull << 63));
    }
    void submit_inst(long long pc, int inst, long long next_pc)
    {
        submit_flag = true;
        cpu_state.pc = next_pc;
        IFONE(CONFIG_ITRACE, ITracer_Data data; data.pc = pc; data.instruction = inst; itracer.save(data));
        Log("submit_inst: PC:0x%08llx inst:0x%08x next_PC:0x%08lx", pc, inst, next_pc);
        inst_cnt++;
    }
    void difftest_memory_access(long long addr)
    {
        if(is_device_addr(addr)) difftest_skip_ref();
    }
#ifdef __cplusplus
}
#endif


void one_cycles()
{

    top->clk = 0;
    top->eval();
    IFONE(CONFIG_CACHE_COUNT, count_cahce());
    count_busy();
    IFONE(CONFIG_WAVE_TRACE, dump_wave());
    top->clk = 1;
    top->eval();
    IFONE(CONFIG_WAVE_TRACE, dump_wave());
    total_cycles++;
    if (total_cycles > SIM_MAX_CYCLES)
    {
        Log("sim cycles: %d is over max: %d", total_cycles, SIM_MAX_CYCLES);
        continue_flag = false;
        sim_finish = true;
    }
}

void cpu_exec_once()
{
    submit_flag = false;
    
    IFONE(CONFIG_DIFFTEST, uint64_t this_pc = cpu_state.pc);
    uint32_t inst_max_cycles = total_cycles+1000;
    while (!submit_flag && continue_flag && !sim_finish)
    {
        one_cycles();
        if(total_cycles > inst_max_cycles) continue_flag = false;
    }
    updata_cpu_reg(gpr);
    IFONE(CONFIG_DIFFTEST,uint64_t next_pc = cpu_state.pc);
    IFONE(CONFIG_DIFFTEST,difftest_step(this_pc, next_pc));
    IFONE(CONFIG_WATCHPOINT, scan_all_wps());
    IFONE(CONFIG_DEVICE, device_update());
}